package com.practice.J2E.Test;

import cn.hutool.core.collection.CollUtil;
import com.practice.J2E.thread.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author kayn
 * @create 2023-09-15 下午 03:02
 */
public class ThreadTest {

    public static Integer a = 0;

    public static HashMap<Integer,String> map = new HashMap<>();

    public static CountDownLatch countDownLatch;

    private final static String lock = "lock";

    public static void main(String[] args) throws Exception{

//        testThread();

        //创建一个根据需要动态调整大小的线程池。
        //线程池会根据任务的数量来自动增加或减少线程数量。如果线程池中的线程空闲超过60秒，它们将被终止并从池中移除。
//        testCachedThreadPool();

        //创建一个固定大小的线程池，其中包含指定数量（n）的线程。
        //当有新的任务提交时，线程池会保持线程数量不变，直到调用 shutdown() 方法关闭线程池为止。
//        testFixedThreadPool();

        //创建一个包含单个线程的线程池。
        //所有提交给线程池的任务都会按照它们被提交的顺序依次执行
//        testSingleThreadExecutor();

        //创建一个定时执行任务的线程池。
        //允许安排任务在一定的延迟后执行，或者按照固定的时间间隔重复执行
//        testScheduledThreadPool();

        //测试synchronized关键字
//        testSynchronized();

        //创建死锁条件
//        testDeadLock();

        //卖酸奶，一个人做酸奶，十个人买酸奶
        sellYogurt();

    }

    private static void sellYogurt() {

        //酸奶杯数
        int yogurtCount = 3;

        //顾客人数
        int buyerCount = yogurtCount + 2;

        Shop shop = Shop.openShop(new ArrayList<>(),yogurtCount);

        //启动一个子线程模拟酸奶店
        new Thread(new YogurtSeller(yogurtCount,shop)).start();

        //线程池模拟顾客购买
        ExecutorService threadPool = Executors.newCachedThreadPool();

        for (int i = 0; i < buyerCount; i++) {

            threadPool.submit(new YogurtBuyer("顾客" + i,shop));

        }

        threadPool.shutdown();

    }

    private static void testDeadLock() {

        Bread bread1 = new Bread("面包1");
        Bread bread2 = new Bread("面包2");
        Bread bread3 = new Bread("面包3");

        List<Dog> list = CollUtil.newArrayList(
                new Dog(bread1, bread2, "狗狗1"),
                new Dog(bread2, bread3, "狗狗2"),
                new Dog(bread3, bread1, "狗狗3"));

        ExecutorService threadPool = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 3; i++) {

            threadPool.submit(list.get(i));

        }

    }

    private static void testSynchronized() throws InterruptedException {

        countDownLatch = new CountDownLatch(100);

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

        for (int i = 0; i < 100; i++) {

            cachedThreadPool.submit(ThreadTest::addA);

        }

        countDownLatch.await();

        System.out.println(a);

    }

    private static void addA() {

        synchronized (lock) {

            System.out.println(Thread.currentThread().getName() + "获取到锁");

            a++;

            System.out.println(a);

            map.put(a,Thread.currentThread().getName());

            countDownLatch.countDown();

            System.out.println(Thread.currentThread().getName() + "释放锁");

        }

    }

    private static void testScheduledThreadPool() throws Exception {

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(150);

        for (int i = 0; i < 1000000; i++) {

            int finalI = i;

            scheduledExecutorService.submit(() -> System.out.println(Thread.currentThread().getName() + ":" + finalI));

        }

        scheduledExecutorService.shutdown();

    }


    private static void testSingleThreadExecutor() {

        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 100; i++) {

            singleThreadExecutor.submit(ThreadTest::execute);

        }

        singleThreadExecutor.shutdown();

    }

    private static void testFixedThreadPool() {

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

        for (int i = 0; i < 100; i++) {

            fixedThreadPool.submit(ThreadTest::execute);

        }

        fixedThreadPool.shutdown();
    }

    /**
     * 线程池
     */
    private static void testCachedThreadPool() {

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

        for (int i = 0; i < 100; i++) {

            cachedThreadPool.submit(ThreadTest::execute);

        }

        cachedThreadPool.shutdown();

    }


    /**
     * 多线程测试
     */
    private static void testThread() {

        Executors.newFixedThreadPool(10);

        Runnable runnable = () -> System.out.println(Thread.currentThread().getName() + "执行");

        Thread thread = new Thread(runnable);

        thread.start();

    }

    public static void execute() {

        System.out.println(Thread.currentThread().getName() + "执行");

    }

}
